package cn.stimd.spring.jdbc.datasource;

import cn.stimd.spring.transaction.TransactionDefinition;
import cn.stimd.spring.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class DataSourceUtils {

    /**
     * 获取数据库连接
     */
    public static Connection getConnection(DataSource dataSource) throws SQLException {
        //尝试获取线程绑定的连接
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if(conHolder != null && conHolder.getConnection() != null){
            return conHolder.getConnection();
        }

        //从数据源中获取连接
        return dataSource.getConnection();
    }


    /**
     * 释放连接（只有当事务执行完毕才真正释放连接）
     */
    public static void releaseConnection(Connection con, DataSource dataSource) {
        if (con == null) {
            return;
        }

        if (dataSource != null) {
            ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
            if(conHolder != null){
                Connection connection = conHolder.getConnection();
                if(connection != null && (connection == con || connection.equals(con))){
                    //待释放的连接与线程绑定的连接是同一个，说明事务尚未关闭，此时不应当释放连接
                    return;
                }
            }
        }

        //关闭连接
        try {
            con.close();
        } catch (SQLException e) {
            //noop
        }
    }


    /**
     * 当前事务的一些准备工作，包括设置是否只读与隔离级别
     */
    public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition) throws SQLException {
        if (definition != null && definition.isReadOnly()) {
            con.setReadOnly(true);
        }

        Integer previousIsolationLevel = null;
        if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
            int currentIsolation = con.getTransactionIsolation();
            if (currentIsolation != definition.getIsolationLevel()) {
                previousIsolationLevel = currentIsolation;
                con.setTransactionIsolation(definition.getIsolationLevel());
            }
        }

        return previousIsolationLevel;
    }


    /**
     * 在事务结束后，重置Connection上的相关属性
     */
    public static void resetConnectionAfterTransaction(Connection con, Integer previousIsolationLevel) {
        try {
            //恢复原先的隔离级别
            if (previousIsolationLevel != null) {
                con.setTransactionIsolation(previousIsolationLevel);
            }

            if (con.isReadOnly()) {
                con.setReadOnly(false);
            }
        }
        catch (Throwable ex) {
            //noop
        }
    }
}
